from typing import Dict, List, Optional
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
from config.settings import RiskConfig
from events.market_event import SignalEvent
from events.order_event import OrderEvent

'''风险管理器'''
class RiskManager:
    def __init__(self, config: RiskConfig):
        self.config = config
        self.daily_pnl = 0
        self.positions = {}  # 当前持仓
        self.trade_history = []  # 交易历史
        self.last_reset = datetime.now()
        self.available_balance = 100000  # 初始可用资金
        
    def reset_daily_stats(self):
        """重置每日统计"""
        if datetime.now().date() > self.last_reset.date():
            self.daily_pnl = 0
            self.last_reset = datetime.now()
            
    def check_position_size(self, symbol: str, size: float, price: float) -> bool:
        """检查仓位大小是否符合风险控制要求"""
        # 确保价格和大小都是浮点数
        price = float(price)
        size = float(size)
        
        # 计算当前持仓价值
        total_position_value = sum(
            float(pos['size']) * float(pos['price'])
            for pos in self.positions.values()
        )
        
        # 计算新的持仓价值
        new_position_value = total_position_value + (size * price)
        
        # 检查是否超过最大仓位限制
        if new_position_value > self.config.max_position_size * self.available_balance:
            print(f"警告: 仓位大小 ({new_position_value}) 超过最大限制")
            return False
            
        return True
        
    def calculate_position_size(self, 
                              available_balance: float,
                              price: float,
                              volatility: float) -> float:
        """计算建议的持仓规模"""
        # 基础仓位
        base_size = available_balance * self.config.position_sizing_factor
        
        # 根据波动率调整仓位
        volatility_factor = 1 / (1 + volatility)
        adjusted_size = base_size * volatility_factor
        
        return min(
            adjusted_size,
            available_balance * self.config.max_position_size
        )

    def size_position(self, signal: SignalEvent) -> Optional[OrderEvent]:
        """根据交易信号确定仓位大小并生成订单"""
        if not signal:
            return None
            
        # 计算波动率（这里使用一个简单的固定值，实际应该根据市场数据计算）
        volatility = 0.1
        
        # 计算建议仓位大小
        position_size = self.calculate_position_size(
            available_balance=self.available_balance,
            price=signal.price,
            volatility=volatility
        )
        
        # 检查仓位是否符合风险控制要求
        if not self.check_position_size(signal.symbol, position_size, signal.price):
            return None
            
        # 创建订单事件
        order = OrderEvent(
            timestamp=signal.timestamp,
            type='MARKET',  # 市价单
            exchange=signal.exchange,
            symbol=signal.symbol,
            side=signal.side,
            quantity=position_size,
            price=signal.price
        )
        
        return order

    def should_stop_loss(self, 
                        symbol: str,
                        current_price: float) -> bool:
        """检查是否需要止损"""
        if symbol not in self.positions:
            return False
            
        position = self.positions[symbol]
        entry_price = position['entry_price']
        
        # 计算亏损比例
        loss_rate = (current_price - entry_price) / entry_price
        
        return loss_rate <= -self.config.stop_loss_rate
        
    def check_daily_loss_limit(self, pnl: float) -> bool:
        """检查是否达到每日亏损限制"""
        self.reset_daily_stats()
        self.daily_pnl += pnl
        
        return self.daily_pnl <= -self.config.max_daily_loss
        
    def calculate_drawdown(self) -> float:
        """计算当前回撤"""
        if not self.trade_history:
            return 0.0
            
        # 计算累计收益曲线
        cumulative_returns = pd.Series([t['pnl'] for t in self.trade_history]).cumsum()
        
        # 计算历史最大值
        rolling_max = cumulative_returns.expanding().max()
        
        # 计算回撤
        drawdown = (cumulative_returns - rolling_max) / rolling_max
        
        return abs(drawdown.min())
        
    def should_stop_trading(self) -> bool:
        """检查是否应该停止交易"""
        # 检查回撤是否超过限制
        if self.calculate_drawdown() > self.config.max_drawdown:
            return True
            
        # 检查日亏损是否超过限制
        if abs(self.daily_pnl) > self.config.max_daily_loss:
            return True
            
        return False
        
    def update_position(self, 
                       symbol: str,
                       size: float,
                       price: float,
                       side: str):
        """更新持仓信息"""
        if side == 'buy':
            self.positions[symbol] = {
                'size': size,
                'entry_price': price,
                'timestamp': datetime.now()
            }
        else:  # sell
            if symbol in self.positions:
                # 计算盈亏
                entry_price = self.positions[symbol]['entry_price']
                pnl = (price - entry_price) * size
                
                # 记录交易历史
                self.trade_history.append({
                    'symbol': symbol,
                    'entry_price': entry_price,
                    'exit_price': price,
                    'size': size,
                    'pnl': pnl,
                    'timestamp': datetime.now()
                })
                
                # 更新每日盈亏
                self.check_daily_loss_limit(pnl)
                
                # 清除持仓记录
                del self.positions[symbol]
